<<<<<<< HEAD HeadShooter v14 — Stable Master
Tap to Start
3

🗺️ Select Map

Choose your battlefield:

MS: --
Time:01:50
|
Kills:0
|
Deaths:0
|
HS:0
|
KS:0
📊 DEBUG
Map:-
Position:0,0
Arrows:0
Buffs:0
FPS:60
======= initBootSplash(); function startPractice() { gameMode = 'offline'; game.isOnline = false; stopOnlineNetworking(); resetGameStats(); // تأكد أن هذه الدالة موجودة عندك مسبقاً لإنشاء البوتات if (typeof spawnBots === "function") { spawnBots(5); } game.running = true; showCountdown(() => { game.gameStartTime = Date.now(); }); } function createParty() { if (!window.playerName) { checkUserIdentity(); return; } gameMode = 'online'; console.log('Game mode changed to: online'); const maps = ['forest', 'desert', 'city']; const randomMap = maps[Math.floor(Math.random() * maps.length)]; const name = window.playerName || "Soldier"; socket.emit('createRoom', { playerName: name, playerId: window.playerId, map: randomMap }); console.log("إرسال طلب إنشاء غرفة بالخريطة:", randomMap); } // السيرفر سيرد بـ playerReadyUpdate (سطر 451 في السيرفر) socket.on('playerReadyUpdate', (data) => { // هنا سنقوم بتحديث شكل الزر أو قائمة اللاعبين if (data.playerId === socket.id) { const btn = document.getElementById('btnReady'); btn.textContent = data.ready ? "✓ Ready!" : "READY"; btn.style.background = data.ready ? "#6BCF7F" : ""; } // نحتاج أيضاً لتحديث القائمة لإظهار من هو جاهز من البقية }); socket.on('gameStarting', (data) => { if (data && data.roomCode) window.currentRoomCode = data.roomCode; console.log("الكل جاهز.. السيرفر أمر ببداية المعركة!"); // 1. إخفاء كل القوائم واللوبي showScreen('none'); const lobby = document.getElementById('lobbyScreen'); if (lobby) lobby.style.display = 'none'; // 2. إظهار منطقة اللعبة const gameCanvas = document.getElementById('game'); if (gameCanvas) gameCanvas.style.display = 'block'; // 3. تهيئة الصوت للقتال AudioManager.stopMenuMusic(); AudioManager.startGameMusic(); // 4. تشغيل اللعبة ببيانات السيرفر // تأكد أن دالة initOnlineGame موجودة عندك وتستقبل الخريطة واللاعبين if (typeof initOnlineGame === 'function') { initOnlineGame(data.mapKey, data.players); } else { // إذا لم تكن موجودة، استخدم دالة startGame المعدلة للأونلاين startOnlineMatch(data.mapKey, data.players); } if (typeof showCountdown === 'function') { game.isCountdownActive = true; showCountdown(function() { game.isCountdownActive = false; }); } }); socket.on('gameStarted', (data) => { game.gameStartTime = data.startTime || Date.now(); game.serverRemainingSec = GAME_DURATION; game.isCountdownActive = false; }); socket.on('gameEnd', (data) => { if (!game.isOnline) return; game.serverRemainingSec = 0; document.getElementById('timeLeft').textContent = '00:00'; window.__returnLobbyPending = false; if (window.__returnLobbyTimer) clearInterval(window.__returnLobbyTimer); var resultKey = (data && data.roomCode ? data.roomCode : 'no-room') + ':' + (data && data.endedAt ? data.endedAt : 0); if (window.__lastResultsKey === resultKey) return; window.__lastResultsKey = resultKey; if (data && data.roomCode) window.currentRoomCode = data.roomCode; if (data && data.players) { game.players = Object.values(data.players).map(function(p) { return { id: p.id, name: p.name || 'Player', x: p.x || 0, y: p.y || 0, angle: p.angle || 0, hp: p.hp || 0, maxHp: p.maxHp || 3, kills: p.kills || 0, deaths: p.deaths || 0, headshots: p.headshots || 0, killstreak: p.killstreak || 0 }; }); } if (game.running) { endGame(); } else { showGameOverScreen(calculateRankings()); } if (socket && socket.connected) { socket.emit('ackMatchResults'); } }); socket.on('matchResultsPending', (data) => { if (!data || !data.players) return; game.serverRemainingSec = 0; document.getElementById('timeLeft').textContent = '00:00'; window.__returnLobbyPending = false; if (window.__returnLobbyTimer) clearInterval(window.__returnLobbyTimer); if (window.__suppressResultsUntil && Date.now() < window.__suppressResultsUntil) return; var resultKey = (data.roomCode || 'no-room') + ':' + (data.endedAt || 0); if (window.__lastResultsKey === resultKey) return; window.__lastResultsKey = resultKey; gameMode = 'online'; game.isOnline = true; if (data.roomCode) window.currentRoomCode = data.roomCode; game.running = false; game.players = Object.values(data.players).map(function(p) { return { id: p.id, name: p.name || 'Player', x: p.x || 0, y: p.y || 0, angle: p.angle || 0, hp: p.hp || 0, maxHp: p.maxHp || 3, kills: p.kills || 0, deaths: p.deaths || 0, headshots: p.headshots || 0, killstreak: p.killstreak || 0 }; }); showGameOverScreen(calculateRankings()); if (socket && socket.connected) { socket.emit('ackMatchResults'); } }); socket.on('stateUpdate', (data) => { if (!game.isOnline || !data || !data.players) return; if (typeof data.remainingMs === 'number') { game.serverRemainingSec = Math.max(0, Math.floor(data.remainingMs / 1000)); } var nextPlayers = []; data.players.forEach(function(p) { var existing = game.players.find(function(pl){ return pl.id === p.id; }); if (!existing) { existing = { id: p.id, name: p.name || 'Player', x: p.x, y: p.y, angle: p.angle || 0, health: 100, hp: p.hp || 3, maxHp: p.maxHp || 3, kills: p.kills || 0, deaths: p.deaths || 0, killstreak: p.killstreak || 0, hasShield: p.hasShield || false, invisible: p.invisible || false, speedBoost: p.speedBoost || false, shieldExpire: p.shieldExpire || 0, invisExpire: p.invisExpire || 0, speedExpire: p.speedExpire || 0, charging: p.charging || false, deathTime: 0 }; } else { if (p.id === game.myId) { existing._predictedX = existing.x; existing._predictedY = existing.y; existing.x = p.x; existing.y = p.y; } else { var dx = p.x - existing.x; var dy = p.y - existing.y; var lerp = 0.6; if (Math.abs(dx) + Math.abs(dy) > 120) { existing.x = p.x; existing.y = p.y; } else { existing.x += dx * lerp; existing.y += dy * lerp; } } existing.angle = p.angle || existing.angle; existing.hp = p.hp; existing.maxHp = p.maxHp; existing.kills = p.kills; existing.deaths = p.deaths; existing.killstreak = p.killstreak; existing.hasShield = p.hasShield; existing.invisible = p.invisible; existing.speedBoost = p.speedBoost; existing.shieldExpire = p.shieldExpire || 0; existing.invisExpire = p.invisExpire || 0; existing.speedExpire = p.speedExpire || 0; existing.charging = p.charging; } if (p.id === game.myId) { var lastSeq = p.lastProcessedInput || 0; if (game.net && game.net.pendingInputs && game.net.pendingInputs.length) { game.net.pendingInputs = game.net.pendingInputs.filter(function(pi){ return pi.seq > lastSeq; }); var step = NET_TICK_MS / 1000; game.net.pendingInputs.forEach(function(pi){ applyInputToPlayer(existing, pi.input, step); }); } if (game.net && typeof existing._predictedX === 'number' && typeof existing._predictedY === 'number') { var corrX = existing.x - existing._predictedX; var corrY = existing.y - existing._predictedY; var err = Math.sqrt(corrX * corrX + corrY * corrY); if (err > 120) { game.net.correctionX = 0; game.net.correctionY = 0; } else { game.net.correctionX = corrX; game.net.correctionY = corrY; existing.x = existing._predictedX; existing.y = existing._predictedY; } } delete existing._predictedX; delete existing._predictedY; } nextPlayers.push(existing); }); game.players = nextPlayers; var me = game.players.find(function(pl){ return pl.id === game.myId; }); if (me) { document.getElementById('kills').textContent = me.kills || 0; document.getElementById('deaths').textContent = me.deaths || 0; document.getElementById('headshots').textContent = me.headshots || 0; document.getElementById('killstreak').textContent = me.killstreak || 0; game.killstreak = me.killstreak || 0; game.headshotCount = me.headshots || 0; } if (data.projectiles) { var byId = {}; data.projectiles.forEach(function(proj){ byId[proj.id] = proj; }); var nextArrows = []; // try to match server projectiles to local-predicted ones data.projectiles.forEach(function(proj){ if (proj.ownerId !== game.myId) return; var best = null; var bestDist = 9999; for (var i=0; i nowb) { b.active = false; b.takenTime = prev.takenTime || nowb; b.predictedUntil = prev.predictedUntil; } return b; }); } }); socket.on('reconnectedToGame', (data) => { if (!data || !data.players) return; gameMode = 'online'; if (data.roomCode) window.currentRoomCode = data.roomCode; showScreen('none'); const lobby = document.getElementById('lobbyScreen'); if (lobby) lobby.style.display = 'none'; const gameCanvas = document.getElementById('game'); if (gameCanvas) gameCanvas.style.display = 'block'; initOnlineGame(data.mapKey || 'forest', data.players); game.isCountdownActive = false; if (data.startTime) game.gameStartTime = data.startTime; }); socket.on('buffPickup', (data) => { if (!data) return; console.log('[audio-debug] buffPickup', data); var myId = (game && game.myId) ? game.myId : socket.id; var isLocalPlayerBuff = (data.playerId === myId); var p = game.players.find(function(pl){ return pl.id === data.playerId; }); if (!p) { if (isLocalPlayerBuff && typeof AudioManager !== 'undefined') { AudioManager.init(); AudioManager.unlock(); if (data.buffType === 'health') AudioManager.playHealthBuff(); if (data.buffType === 'shield') AudioManager.playShieldBuff(); if (data.buffType === 'invis') AudioManager.playInvisBuff(); if (data.buffType === 'speed') AudioManager.playSpeedBuff(); } return; } // Visual feedback var color = '#FFD93D'; if (data.buffType === 'shield') color = '#4D96FF'; if (data.buffType === 'invis') color = '#C77DFF'; if (data.buffType === 'speed') color = '#FFD93D'; if (data.buffType === 'health') color = '#6BCF7F'; createParticles(p.x, p.y, 18, color); // Local audio only for the player who picked it if (isLocalPlayerBuff && typeof AudioManager !== 'undefined') { AudioManager.init(); AudioManager.unlock(); if (data.buffType === 'health') AudioManager.playHealthBuff(); if (data.buffType === 'shield') AudioManager.playShieldBuff(); if (data.buffType === 'invis') AudioManager.playInvisBuff(); if (data.buffType === 'speed') AudioManager.playSpeedBuff(); } var b = game.buffs.find(function(bb){ return bb.id === data.buffId; }); if (b) { b.active = false; b.takenTime = Date.now(); b.predictedUntil = 0; } }); socket.on('shieldBreak', (data) => { if (!data) return; var p = game.players.find(function(pl){ return pl.id === data.playerId; }); if (!p) return; createParticles(p.x, p.y, 15, '#4D96FF'); }); socket.on('hitEffect', (data) => { if (!data) return; if (data.type === 'player' && data.headshot) { console.log('[audio-debug] headshot hitEffect', data); } var color = '#FFD93D'; var count = 8; if (data.type === 'shield') { color = '#4D96FF'; count = 12; } else if (data.type === 'player') { color = data.headshot ? '#FF4444' : '#FFD93D'; count = data.headshot ? 16 : 10; } else if (data.type === 'map') { color = '#FFD93D'; count = 8; } if (typeof data.x === 'number' && typeof data.y === 'number') { createParticles(data.x, data.y, count, color); } // Headshot sound should play only for the killer (handled in playerKilled) }); socket.on('playerKilled', (data) => { if (!data) return; var killer = game.players.find(function(pl){ return pl.id === data.killerId; }); var victim = game.players.find(function(pl){ return pl.id === data.victimId; }); var now = Date.now(); if (killer) { var chainCount = data.chainCount || 0; killer.killChain = chainCount; killer.killChainTime = now; if (!game.killChains[killer.id]) game.killChains[killer.id] = { count: 0, lastKillTime: 0 }; game.killChains[killer.id].count = chainCount; game.killChains[killer.id].lastKillTime = now; } // Kill feed entry game.killFeed.push({ killer: (killer && killer.name) || 'Unknown', victim: (victim && victim.name) || 'Player', isHeadshot: !!data.isHeadshot, chainColor: getKillChainColor(data.chainCount || 0), time: now }); if (game.killFeed.length > 5) game.killFeed.shift(); // Skull effect + headshot sound for killer if (data.isHeadshot && victim) { game.skullEffects.push({ x: victim.x, y: victim.y, time: now }); } var isMyKill = (data.killerId === socket.id); if (data.isHeadshot && isMyKill && typeof AudioManager !== 'undefined') { AudioManager.init(); AudioManager.unlock(); AudioManager.playSkullcrushSafe(); } if (isMyKill) { if (data.chainCount && data.chainCount >= 2) { showChainAlert(data.chainCount); var chainName = getKillChainName(data.chainCount); var chainCol = getKillChainColor(data.chainCount); game.killFeed.push({ killer: (killer && killer.name) || 'You', victim: 'achieved ' + chainName + '!', isHeadshot: false, chainColor: chainCol, time: now }); if (game.killFeed.length > 5) game.killFeed.shift(); } if (data.killstreakTier) { var ksMap = { extraCore: { text: 'EXTRA CORE', color: '#6BCF7F', tier: 1 }, momentum: { text: 'MOMENTUM', color: '#FFD93D', tier: 2 }, fastCharge: { text: 'FAST CHARGE', color: '#C77DFF', tier: 3 }, steadyAim: { text: 'STEADY AIM', color: '#4D96FF', tier: 4 }, legendary: { text: 'LEGENDARY!', color: '#800000', tier: 5 } }; var ks = ksMap[data.killstreakTier]; if (ks) { showKillstreakAlert(ks.text, ks.color, ks.tier); if (killer) { createKillstreakAnimation(killer, killer.killstreak || ks.tier, ks.color); } } } if (killer && data.killstreakTier) { var now2 = Date.now(); if (data.killstreakTier === 'extraCore' && !killer.hasExtraCore) { killer.hasExtraCore = true; killer.maxHp = 4; killer.hp = Math.min((killer.hp || 3) + 1, killer.maxHp); } else if (data.killstreakTier === 'momentum' && !killer.hasMomentum) { killer.hasMomentum = true; killer.momentumActive = true; killer.momentumStart = now2; } else if (data.killstreakTier === 'fastCharge' && !killer.hasFastCharge) { killer.hasFastCharge = true; killer.fastChargeActive = true; killer.fastChargeStart = now2; } else if (data.killstreakTier === 'steadyAim' && !killer.hasSteadyAim) { killer.hasSteadyAim = true; killer.steadyAimActive = true; killer.steadyAimStart = now2; } else if (data.killstreakTier === 'legendary' && !killer.hasLegendary) { killer.hasLegendary = true; killer.legendaryActive = true; killer.legendaryStart = now2; if (killer.hasMomentum) { killer.momentumActive = true; killer.momentumStart = now2; } if (killer.hasFastCharge) { killer.fastChargeActive = true; killer.fastChargeStart = now2; } if (killer.hasSteadyAim) { killer.steadyAimActive = true; killer.steadyAimStart = now2; } } updateKillstreakPassives(killer); } if (killer && data.isHeadshot) { killer.headshots = (killer.headshots || 0) + 1; } } if (victim && victim.id === game.myId) { game.chainAlert = null; if (game.killChains[game.myId]) { game.killChains[game.myId].count = 0; game.killChains[game.myId].lastKillTime = 0; } victim.killstreak = 0; victim.killChain = 0; victim.killChainTime = 0; victim.maxHp = 3; victim.hasExtraCore = false; victim.hasMomentum = false; victim.momentumActive = false; victim.hasFastCharge = false; victim.fastChargeActive = false; victim.hasSteadyAim = false; victim.steadyAimActive = false; victim.hasLegendary = false; victim.legendaryActive = false; } if (victim) { createParticles(victim.x, victim.y, 12, '#FF4444'); } // Local HUD refresh var me = game.players.find(function(pl){ return pl.id === game.myId; }); if (me) { document.getElementById('kills').textContent = me.kills || 0; document.getElementById('deaths').textContent = me.deaths || 0; document.getElementById('headshots').textContent = me.headshots || 0; document.getElementById('killstreak').textContent = me.killstreak || 0; game.killstreak = me.killstreak || 0; game.headshotCount = me.headshots || 0; } }); socket.on('projectileFired', (proj) => { if (!proj) return; console.log('[audio-debug] projectileFired', proj.ownerId, 'me=', socket.id); if (proj.ownerId && proj.ownerId !== socket.id && typeof AudioManager !== 'undefined') { var lp = game.players.find(function(pl){ return pl.id === game.myId || pl.id === socket.id; }); if (!lp) return; var pad = 200; var inView = (proj.x >= game.camera.x - pad && proj.x <= game.camera.x + c.width + pad && proj.y >= game.camera.y - pad && proj.y <= game.camera.y + c.height + pad); if (!inView) return; AudioManager.init(); AudioManager.unlock(); AudioManager.playEnemyShot(); } }); // --- في ملف index.html --- socket.on('playerJoined', (data) => { console.log("لاعب جديد انضم للوبي!"); if (data.roomCode) window.currentRoomCode = data.roomCode; if (data.leaderId) window.currentLeaderId = data.leaderId; showScreen('lobbyScreen'); // ينقلك لشاشة الانتظار فوراً updateLobbyPlayers(data.players, data.leaderId, data.roomCode); // يظهر أسماء اللاعبين في الخانات }); // أضف هذا بجانب socket.on('playerJoined') socket.on('updatePlayers', (data) => { console.log("تحديث قائمة اللاعبين...", data); updateLobbyPlayers(data.players, data.leaderId, data.roomCode); }); socket.on('lobbyUpdate', (data) => { if (!data || !data.players) return; if (window.__inResultsFlow) { window.__pendingLobbyUpdate = data; return; } if (document.getElementById('gameOverScreen')) { document.getElementById('gameOverScreen').style.display = 'none'; } gameMode = 'online'; if (data.roomCode) window.currentRoomCode = data.roomCode; if (data.leaderId) window.currentLeaderId = data.leaderId; updateLobbyPlayers(data.players, data.leaderId, data.roomCode); if (window.__returnLobbyPending) { window.__returnLobbyPending = false; if (window.__returnLobbyTimer) clearInterval(window.__returnLobbyTimer); showScreen('lobbyScreen'); } }); socket.on('lobbySnapshot', (data) => { if (!data || !data.players) return; if (window.__inResultsFlow) { window.__pendingLobbySnapshot = data; return; } if (document.getElementById('gameOverScreen')) { document.getElementById('gameOverScreen').style.display = 'none'; } window.__returnLobbyPending = false; if (window.__returnLobbyTimer) clearInterval(window.__returnLobbyTimer); gameMode = 'online'; if (data.roomCode) window.currentRoomCode = data.roomCode; if (data.leaderId) window.currentLeaderId = data.leaderId; updateLobbyPlayers(data.players, data.leaderId, data.roomCode); showScreen('lobbyScreen'); }); socket.on('joinError', (data) => { alert(data && data.message ? data.message : 'Join failed'); if (window.__returnLobbyPending) { window.__returnLobbyPending = false; if (window.__returnLobbyTimer) clearInterval(window.__returnLobbyTimer); showScreen('gameModeMenu'); } }); function showAntiCheatToast(message, bgColor, durationMs) { var prev = document.getElementById('antiCheatToast'); if (prev && prev.parentNode) prev.parentNode.removeChild(prev); var el = document.createElement('div'); el.id = 'antiCheatToast'; el.textContent = message || 'Anti-cheat action applied'; el.style.position = 'fixed'; el.style.left = '50%'; el.style.top = '16px'; el.style.transform = 'translateX(-50%)'; el.style.zIndex = '999999'; el.style.padding = '10px 16px'; el.style.borderRadius = '12px'; el.style.fontWeight = '800'; el.style.fontSize = '14px'; el.style.color = '#fff'; el.style.background = bgColor || 'rgba(17,24,39,0.96)'; el.style.boxShadow = '0 8px 24px rgba(0,0,0,0.35)'; el.style.border = '1px solid rgba(255,255,255,0.2)'; document.body.appendChild(el); setTimeout(function(){ if (el && el.parentNode) el.parentNode.removeChild(el); }, durationMs || 2200); } socket.on('antiCheatAction', function(data) { if (!data || !data.action) return; var until = data.until || 0; var leftMs = Math.max(0, until - Date.now()); if (data.action === 'warn') { showAntiCheatToast('Warning: suspicious behavior detected', 'rgba(234,179,8,0.96)', 2200); return; } if (data.action === 'softBlock') { var secs = Math.max(1, Math.ceil(leftMs / 1000)); showAntiCheatToast('Fire blocked for ' + secs + 's', 'rgba(249,115,22,0.96)', 2600); return; } if (data.action === 'hardBlock') { var secs2 = Math.max(1, Math.ceil(leftMs / 1000)); showAntiCheatToast('Input blocked for ' + secs2 + 's', 'rgba(220,38,38,0.96)', 3000); return; } showAntiCheatToast('Anti-cheat action: ' + data.action, 'rgba(17,24,39,0.96)', 2200); }); socket.on('kickedFromParty', () => { window.currentRoomCode = null; window.currentLeaderId = null; window.__returnLobbyPending = false; if (window.__returnLobbyTimer) clearInterval(window.__returnLobbyTimer); game.running = false; game.isOnline = false; game.isCountdownActive = false; stopOnlineNetworking(); if (game.animationId) cancelAnimationFrame(game.animationId); showModal({ title: 'Removed From Party', body: 'The leader removed you from the party.', confirmText: 'OK', showCancel: false, onConfirm: function() { showScreen('gameModeMenu'); } }); }); socket.on('newLeader', (data) => { console.log("New leader assigned:", data.leaderId); if (data.leaderId) window.currentLeaderId = data.leaderId; // إذا كنت أنت الليدر الجديد، ستتغير واجهتك في التحديث القادم // سنعيد طلب تحديث القائمة لضمان ظهور أزرار التحكم لك // (دالة updateLobbyPlayers التي برمجناها سابقاً ستتكفل بالباقي) // إعادة رسم اللوبي لتحديث الأزرار if (window.currentLobbyPlayers) { updateLobbyPlayers(window.currentLobbyPlayers, data.leaderId, window.currentRoomCode); } }); // تأكد أيضاً من إضافة مستمع لخروج اللاعبين لتحديث القائمة فوراً socket.on('playerLeft', (data) => { if (data && data.players) { updateLobbyPlayers(data.players); } }); // عندما ينجح إنشاء الغرفة // استقبال رد السيرفر عند إنشاء غرفة جديدة بنجاح socket.on('roomCreated', (data) => { console.log("Room created successfully:", data.roomCode); // تحديث الكود في الشاشة const roomCodeDisplay = document.getElementById('roomCodeText'); if (roomCodeDisplay) { roomCodeDisplay.textContent = data.roomCode; console.log('Room code updated to:', data.roomCode); } else { console.error('roomCodeText element not found!'); } // حفظ الكود عشان نستخدمه لاحقاً window.currentRoomCode = data.roomCode; if (data.leaderId) window.currentLeaderId = data.leaderId; // تحديث اللاعبين updateLobbyPlayers(data.players, data.leaderId, data.roomCode); // الانتقال للوبي showScreen('lobbyScreen'); }); // عندما ينضم لاعب جديد للغرفة socket.on('roomJoined', (data) => { if (data.roomCode) { window.currentRoomCode = data.roomCode; document.getElementById('roomCodeText').textContent = data.roomCode; } updateLobbyPlayers(data.players, data.leaderId, data.roomCode); showScreen('lobbyScreen'); }); // إذا حدث خطأ (مثلاً الكود غلط) socket.on('error', (data) => { // نأخذ النص الموجود داخل الخاصية message alert(data.message || "An error occurred"); }); window.toggleReady = function() { if (gameMode !== 'online') { console.log('Not in online mode'); return; } console.log("إرسال طلب تغيير الجاهزية للسيرفر..."); socket.emit('playerReady'); }; function joinParty() { if (!window.playerName) { checkUserIdentity(); return; } gameMode = 'online'; console.log('Game mode changed to: online'); showScreen('joinScreen'); } // السطر 3423 - استبدل الدالة كاملة: function updateLobbyPlayers(players, leaderIdParam, roomCodeParam) { window.currentLobbyPlayers = players; const playerEntries = Object.entries(players || {}); const playerArray = playerEntries.map(function(e){ return e[1]; }); if (playerArray.length === 0) { console.log('No players in lobby'); return; } // تحديد القائد من السيرفر إن توفر const leaderId = leaderIdParam || window.currentLeaderId || (playerArray[0] && playerArray[0].id); const myPid = window.playerId || ''; const isLeader = playerEntries.some(function(entry){ var key = entry[0]; var p = entry[1]; if (!p) return false; if (key === leaderId && (p.id === socket.id || p.persistentId === myPid || key === socket.id)) return true; if (p.id === leaderId && (p.id === socket.id || p.persistentId === myPid || key === socket.id)) return true; return false; }); console.log('Updating lobby:', { myId: socket.id, leaderId: leaderId, isLeader: isLeader, playerCount: playerArray.length }); const lobbyGrid = document.getElementById('lobbyGrid'); const roomCodeDisplay = document.getElementById('roomCodeContainer'); const roomCodeText = document.getElementById('roomCodeText'); if (!lobbyGrid) { console.error('lobbyGrid not found!'); return; } // إظهار/إخفاء رمز الغرفة (للقائد فقط) if (roomCodeDisplay && roomCodeText) { if (isLeader) { roomCodeDisplay.style.display = 'block'; // ← أظهر الصندوق roomCodeText.textContent = roomCodeParam || window.currentRoomCode || '-----'; } else { roomCodeDisplay.style.display = 'none'; // ← أخفي الصندوق للاعبين } } // مسح القائمة lobbyGrid.innerHTML = ''; // رسم 6 خانات for (let i = 0; i < 6; i++) { const slot = document.createElement('div'); slot.className = 'lobby-slot'; if (playerEntries[i]) { const playerKey = playerEntries[i][0]; const p = playerEntries[i][1]; const isPlayerLeader = (playerKey === leaderId) || (p.id === leaderId); const isMe = (p.id === socket.id) || (playerKey === socket.id) || (myPid && p.persistentId === myPid); slot.classList.add('occupied'); // أضف كلاس ready إذا كان جاهز أو قائد if (p.ready || isPlayerLeader) { slot.classList.add('ready'); } // تحديد النص let statusText = ''; if (isPlayerLeader) { statusText = '[LEADER - READY]'; } else if (p.disconnected) { statusText = '[OFFLINE]'; } else if (p.ready) { statusText = '[READY]'; } else { statusText = '[NOT READY]'; } const canKick = isLeader && !isPlayerLeader; const kickHtml = canKick ? `` : ''; slot.innerHTML = ` ${isPlayerLeader ? '[L] ' : ''}${p.name}${isMe ? ' (You)' : ''} ${statusText} ${kickHtml} `; } else { slot.classList.add('empty'); slot.innerHTML = `Waiting for player...`; } lobbyGrid.appendChild(slot); } // إظهار/إخفاء الأزرار حسب الدور const btnStart = document.getElementById('btnStartGame'); const btnReady = document.getElementById('btnReady'); if (isLeader) { if (btnStart) btnStart.style.display = 'block'; if (btnReady) btnReady.style.display = 'none'; } else { if (btnStart) btnStart.style.display = 'none'; if (btnReady) { btnReady.style.display = 'block'; // تحديث شكل الزر const myEntry = playerEntries.find(function(entry){ var key = entry[0]; var p = entry[1]; return p && (p.id === socket.id || key === socket.id || (myPid && p.persistentId === myPid)); }); const myPlayer = myEntry ? myEntry[1] : null; if (myPlayer) { btnReady.textContent = myPlayer.ready ? '✓ READY' : 'READY'; btnReady.style.background = myPlayer.ready ? 'linear-gradient(135deg, #6BCF7F, #4D96FF)' : 'linear-gradient(135deg, #667eea, #764ba2)'; } } } } window.kickPlayer = function(playerKey, playerId, evt) { if (evt) { evt.preventDefault(); evt.stopPropagation(); } if (!playerKey || !socket || !socket.connected) return; var players = window.currentLobbyPlayers || {}; var target = players[playerKey] || Object.values(players).find(function(p){ return p && p.id === playerId; }); var targetName = target && target.name ? target.name : 'player'; setTimeout(function() { showModal({ title: 'Kick Player', body: 'Are you sure you want to kick "' + targetName + '" ?', confirmText: 'Yes, Kick', cancelText: 'Cancel', showCancel: true, onConfirm: function() { socket.emit('kickPlayer', { playerKey: playerKey, playerId: playerId || '' }); } }); }, 0); }; function leaveRoom() { const leaderId = window.currentLeaderId; const isLeader = (leaderId && socket.id === leaderId); const msg = isLeader ? "Are you sure you want to cancel the party?" : "Leave this party?"; showModal({ title: 'Leave Party', body: msg, confirmText: 'Yes, Leave', cancelText: 'No, Stay', showCancel: true, onConfirm: () => { socket.emit('leaveRoom'); window.currentRoomCode = null; window.currentLeaderId = null; showScreen('gameModeMenu'); // العودة لصفحة القيم مود } }); } window.requestStartFromServer = function() { console.log("إرسال طلب بدء اللعبة للسيرفر..."); if (typeof socket !== 'undefined' && socket.connected) { socket.emit('startGame'); } else { alert("السيرفر غير متصل!"); } }; })(); >>>>>>> 994a45c5850e9eb5140dc6919318c2b441e96a7a